package com.dataseek.iot.device.manager.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dataseek.iot.core.base.IController;
import com.dataseek.iot.core.constant.ResponseConst;
import com.dataseek.iot.core.request.QueryPage;
import com.dataseek.iot.core.request.QueryPage2;
import com.dataseek.iot.core.request.QueryParam;
import com.dataseek.iot.core.response.ResponseEntity;
import com.dataseek.iot.core.util.ParseUtil;
import com.dataseek.iot.core.util.WrapperUtil;
import com.dataseek.iot.device.manager.handler.ControlHandler;
import com.dataseek.iot.device.manager.vo.FunctionParamVo;
import com.dataseek.iot.device.manager.vo.InputVo;
import com.dataseek.iot.device.manager.vo.InvokeVo;
import com.dataseek.iot.mqtt.service.MqttGateway;
import com.dataseek.iot.mysql.entity.Control;
import com.dataseek.iot.mysql.entity.FunctionLog;
import com.dataseek.iot.mysql.service.impl.FunctionLogServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author cc
 * @since 2021-09-23
 */
@RestController
@RequestMapping("/control")
@Api(tags = "远控接口")
public class ControlController implements IController<Control> {

    @Autowired
    MqttGateway mqttGateway;

    @Autowired
    FunctionLogServiceImpl functionLogService;

    static Map<String, Integer> idMap;

    static {
        idMap = new HashMap();
    }

    @Autowired
    ControlHandler controlService;

    @PutMapping("/addOne")
    @ApiOperation("保存单个远控属性")
    @Override
    public Mono<ResponseEntity> saveOne(@RequestBody Control entity) {
        Control user = entity;
        return controlService.saveOne(user);
    }

    @PostMapping("/addBatch")
    @ApiOperation("批量保存远控属性数据")
    @Override
    public Mono<ResponseEntity> saveBatch(@RequestBody List<Control> lists) {
        return controlService.saveBatch(lists);
    }


    @DeleteMapping("/{id}")
    @ApiOperation("根据ID移除远控属性信息")
    @Override
    public Mono<ResponseEntity> remove(@PathVariable String id) {
        return controlService.remove(id);
        //TODO 校验关联的其他信息
    }

    @DeleteMapping("/removeByIds")
    @ApiOperation("根据ID批量移除远控属性信息")
    @Override
    public Mono<ResponseEntity> removeAll(@RequestBody List<String> ids) {
        return controlService.removeAll(ids);
        //TODO 校验关联的其他信息
    }

    @DeleteMapping("/remove")
    @ApiOperation("根据条件移除远控属性信息")
    @Override
    public Mono<ResponseEntity> remove(@RequestBody List<QueryParam> params) {
        Wrapper wrapper = WrapperUtil.assembleParams(params);
        return controlService.remove(wrapper);
        //TODO 校验关联的其他信息
    }

    @PostMapping("/updateOne")
    @ApiOperation("更新远控属性信息")
    @Override
    public Mono<ResponseEntity> updateOne(@RequestBody Control entity) {
        return controlService.updateOne(entity);
    }

    @PostMapping("/update")
    @ApiOperation("根据条件更新远控属性信息")
    @Override
    public Mono<ResponseEntity> update(@RequestBody List<QueryParam> params) {
        Wrapper wrapper = WrapperUtil.assembleParams(params);
        return controlService.update(wrapper);
    }

    @PostMapping("/updatePassword")
    @ApiOperation("更新密码")
    public Mono<ResponseEntity> updatePassword(@RequestBody Control user) {
        return controlService.updateOne(user);
    }

    @PostMapping("/updateBatch")
    @ApiOperation("批量更新")
    @Override
    public Mono<ResponseEntity> updateBatch(@RequestBody List<Control> entities) {
        return controlService.updateBatch(entities);
    }

    @PostMapping("/page/find")
    @ApiOperation("无条件分页查询")
    @ApiImplicitParams(
            @ApiImplicitParam(name = "page", value = "分页对象", required = true,
                    example = "{" +
                            " //当前页面，默认1" +
                            "  current: 0," +
                            " //是否命中count缓存 默认为 false" +
                            "  hitCount: true," +
                            "//单页分页条数限制" +
                            "  maxLimit: 4," +
                            "  //排序字段设置" +
                            "  orders: [" +
                            "    {asc: true, column: username }" +
                            "  ]," +
                            "  searchCount: true," +
                            " //每页条数" +
                            "  size: 10," +
                            "}")
    )
    @Override
    public Mono<ResponseEntity> page(@RequestBody Page p) {
        return controlService.page(p);
    }

    @PostMapping("/page/findWithParam")
    @ApiOperation("分页查询，带查询条件")
    @Override
    public Mono<ResponseEntity> page(@RequestBody QueryPage queryPage) {
        if (queryPage == null || queryPage.getParams() == null || queryPage.getPage() == null) {
            ResponseEntity entity = new ResponseEntity();
            entity.setCode(ResponseConst.BAD_REQUEST_CODE);
            entity.setMsg(ResponseConst.BAD_REQUEST);
            return controlService.defaultResponseOne(entity);
        }
        return controlService.page(queryPage.getPage(), WrapperUtil.assembleParams(queryPage.getParams()));
    }

    /**
     * 根据IDS查询数据
     *
     * @param ids
     * @return
     */
    @PostMapping("/findById")
    @ApiOperation("根据ID查询数据")
    @Override
    public Flux<ResponseEntity> findByIds(@RequestBody List<String> ids) {
        return controlService.find(ids);
    }

    /**
     * 根据查询条件查询数据
     *
     * @param params
     * @return
     */
    @PostMapping("/findByParams")
    @ApiOperation("根据查询条件查询参数")
    @Override
    public Flux<ResponseEntity> find(@RequestBody List<QueryParam> params) {
        ResponseEntity entity = new ResponseEntity();
        if (params == null) {
            entity.setCode(ResponseConst.BAD_REQUEST_CODE);
            entity.setMsg(ResponseConst.BAD_REQUEST);
            return controlService.defaultResponseTwo(entity);
        } else if (params.size() == 0) {
            entity.setCode(ResponseConst.NULL_PARAM_CODE);
            entity.setMsg(ResponseConst.NULL_PARAM);
            return controlService.defaultResponseTwo(entity);
        }
        return controlService.find(WrapperUtil.assembleParams(params));
    }

    /**
     * 根据id条件查询数据
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @ApiOperation("根据ID查询远控属性")
    @Override
    public Mono<ResponseEntity> findOne(@PathVariable String id) {
        return controlService.findOne(id);
    }

    /**
     * 查询所有数据
     *
     * @return
     */
    @GetMapping("/findAll")
    @ApiOperation("查询所有")
    @Override
    public Flux<ResponseEntity> findAll() {
        return controlService.findAll();
    }

    @PostMapping("/findByJSONParams")
    @ApiOperation("条件查询，没有分页")
    @Override
    public Flux<ResponseEntity> find(@RequestBody JSONObject json) {
        QueryWrapper wrapper = ParseUtil.parseJson(json);
        return controlService.find(wrapper);
    }

    @PostMapping("/page/findByJSONParams")
    @ApiOperation("分页查询，传参为json")
    @Override
    public Mono<ResponseEntity> page(@RequestBody JSONObject json) {
        QueryPage2 queryPage2 = ParseUtil.parseJsonWithPage(json);
        return controlService.page(queryPage2.getPage(), queryPage2.getWrapper());
    }

    @PostMapping("/remote/control")
    @ApiOperation("远控接口")
    public Mono<ResponseEntity> remoteControl(@RequestBody FunctionParamVo functionVo) {
        ResponseEntity entity = new ResponseEntity();
        String productCode = functionVo.getProductCode();
        String deviceCode = functionVo.getDeviceCode();
        Long currentTimeMillis = System.currentTimeMillis();
        String messageId;
        if(idMap.containsKey(deviceCode)){
            Integer suffixNum = idMap.get(deviceCode);
            suffixNum++;
            messageId = deviceCode + "(" + "function-" + suffixNum + ")";
            idMap.put(deviceCode, suffixNum);
        }else {
            idMap.put(deviceCode, 0);
            messageId = deviceCode + "(" + "function-0" + ")";
        }

        List<InputVo> inputs = functionVo.getInputs();
        //功能指令下行topic
        StringBuffer fb = new StringBuffer();
        fb.append("/").append(productCode).append("/").append(deviceCode).append("/").append("function/invoke");
        InvokeVo invokeVo = new InvokeVo();
        invokeVo.setInputs(inputs);
        invokeVo.setDeviceId(deviceCode);
        invokeVo.setTimestamp(currentTimeMillis);
        invokeVo.setMessageId(messageId);
        invokeVo.setFunction(functionVo.getFunction());
        //组装功能日志
        FunctionLog log = new FunctionLog();
        log.setProductCode(productCode);
        log.setDeviceCode(deviceCode);
        log.setMessageId(messageId);
        log.setTimestamp(currentTimeMillis);
        log.setInput(JSON.toJSONString(functionVo.getInputs()));
        log.setFunctionCode(functionVo.getFunction());
//        log.setFunction(functionVo.getFunction());
//        if(functionVo.getInputs().size()>0) {
//            InputVo inputVos = functionVo.getInputs().get(0);
//            log.setInputName(inputVos.getName());
//            log.setInputValue(inputVos.getValue());
//        }else {
//            entity.setData(ResponseConst.CRUD_FAILED_CODE);
//            entity.setMsg("控制参数为空");
//            entity.setData("");
//        }
        try {
            mqttGateway.sendToMqtt(fb.toString(), JSON.toJSONString(invokeVo));
            entity.setCode(ResponseConst.SUCCESS_CODE);
            entity.setMsg("功能指令发送成功");
            entity.setData("");
            functionLogService.save(log);
        } catch (MqttException e) {
            entity.setCode(ResponseConst.SEND_FAILED_CODE);
            entity.setMsg(ResponseConst.SEND_FAILED);
            entity.setData("");
            e.printStackTrace();
        }
        return Mono.just(entity);
    }

}
